﻿using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;

namespace ResxHelperGenerator;

[Generator]
#pragma warning disable RS1036 // Specify analyzer banned API enforcement setting
public class CultureHelperGenerator : ISourceGenerator
#pragma warning restore RS1036 // Specify analyzer banned API enforcement setting
{
    public void Initialize(GeneratorInitializationContext context)
    {
        // No initialization required for this one
    }

    public void Execute(GeneratorExecutionContext context)
    {
#if DEBUG
        if (!Debugger.IsAttached)
        {
            // Uncomment to debug
            // Debugger.Launch();
        }
#endif

        if (InitialCheckUp(context, out string projectRootPath, out string projectRootNamespace))
        {
            string[] cultures = DetectAllCultures(context);

            if (!context.CancellationToken.IsCancellationRequested)
            {
                GenerateAvailableCultureListSourceFile(context, projectRootNamespace, cultures);
            }
        }
    }

    private bool InitialCheckUp(GeneratorExecutionContext context, out string projectRootPath, out string projectRootNamespace)
    {
        projectRootPath = null;
        projectRootNamespace = null;

        if (context.Compilation is not CSharpCompilation)
        {
            // the converter only support C# for the moment
            context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor(
                "RHG0001",
                "Language not supported",
                "ResxHelperGenerator source generator only supports C#.",
                "ResxHelperGenerator.Errors",
                DiagnosticSeverity.Error,
                true), (Location)null));
            return false;
        }

        // retrieve the project settings.
        if (!context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.DefaultLanguage", out _)
            || !context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.RootNamespace", out projectRootNamespace)
            || !context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.MSBuildProjectFullPath", out string projectFileFullPath)
            || !context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.OutputType", out _))
        {
            // error
            context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor(
             "RHG0002",
             "Build properties missing",
             "Build properties are not exposed to ResxHelperGenerator source generator",
             "ResxHelperGenerator.Errors",
             DiagnosticSeverity.Error,
             true), (Location)null));
            return false;
        }

        projectRootPath = Path.GetDirectoryName(projectFileFullPath);
        return true;
    }

    private string[] DetectAllCultures(GeneratorExecutionContext context)
    {
        var cultures = new HashSet<string>() { "en-US" };

        var resxFiles = context.AdditionalFiles.Where(f => Path.GetExtension(f.Path).ToLower() == ".resx").ToList();
        for (int i = 0; i < resxFiles.Count; i++)
        {
            string filePath = resxFiles[i].Path.Trim();
            string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath);
            string cultureName = fileNameWithoutExtension.Split(new[] { '.' }, System.StringSplitOptions.RemoveEmptyEntries).Last();
            if (cultureName.Length == 2 || (cultureName.Length >= 5 && cultureName.Length <= 7 && cultureName.Contains("-")))
            {
                cultures.Add(cultureName);
            }
        }

        return cultures.ToArray();
    }

    private void GenerateAvailableCultureListSourceFile(GeneratorExecutionContext context, string projectRootNamespace, string[] cultures)
    {
        var builder = new StringBuilder();
        builder.AppendLine("//------------------------------------------------------------------------------");
        builder.AppendLine("// <auto-generated>");
        builder.AppendLine("//     This code was generated by ResxHelperGenerator.");
        builder.AppendLine("//");
        builder.AppendLine("//     Changes to this file may cause incorrect behavior and will be lost if");
        builder.AppendLine("//     the code is regenerated.");
        builder.AppendLine("// </auto-generated>");
        builder.AppendLine("//------------------------------------------------------------------------------");
        builder.AppendLine("");
        builder.AppendLine($"namespace {projectRootNamespace};");
        builder.AppendLine("");
        builder.AppendLine("public static class CultureHelper");
        builder.AppendLine("{");
        builder.AppendLine("    public static readonly string[] ApplicationCultures");
        builder.AppendLine("        = new string[]");
        builder.AppendLine("        {");

        for (int i = 0; i < cultures.Length; i++)
        {
            builder.AppendLine($"            \"{cultures[i]}\",");
        }

        builder.AppendLine("        };");
        builder.AppendLine("}");

        string sourceCode = builder.ToString();
        context.AddSource("CultureHelper.g.cs", SourceText.From(sourceCode, Encoding.UTF8));
    }
}
